// Copyright (c) 2020 InCore Semiconductors Pvt. Ltd. see LICENSE.incore for more details on licensing terms
/*
Author: Neel Gala, neelgala@incoresemi.com
Created on: Friday 01 May 2020 05:19:02 PM IST

*/
package Soc ;

import FIFOF          :: * ;
import Vector         :: * ;
import SpecialFIFOs   :: * ;
import FIFOF          :: * ;
import Connectable    :: * ;
import GetPut         :: * ;

`include "Logger.bsv"
`include "Soc_map.bsv"
import Soc_instances  :: * ;
import qspi           :: * ;
import uart           :: * ;
import bootconfig     :: * ;
import clint          :: * ;
import plic           :: * ;
import gpio           :: * ;
import pwm            :: * ;
import spi            :: * ;
import spi_cluster    :: * ;
import ram2rw         :: * ;
import rom            :: * ;
import ram1rw         :: * ;
import riscv_debug    :: * ;
import debug_loop     :: * ;
import axi4           :: * ;
import axi4l          :: * ;
import apb            :: * ;
import ccore          :: * ;
import ccore_types    :: * ;
import bridges        :: * ;
import DCBus          :: * ;
import riscv_debug_types :: * ;

interface Ifc_Soc;
    (*prefix="uart0"*)
    interface RS232#(16) ifc_uart0;
    (*always_ready, always_enabled, prefix=""*)
    method Action boot_config ((*port = "boot_config"*) Bit#(2) conf);
    (*prefix=""*)
    interface GPIO#(22)  ifc_gpio;
    (*prefix=""*)
    interface PWMIO#(`channels, `comp_out_en)  ifc_pwm;
    (*prefix="spi0"*)
    interface SPI_IO#(1) ifc_spi0; // used for flash
    (*prefix="spi1"*)
    interface SPI_IO#(2) ifc_spi1;
    (*prefix="spi2"*)
    interface SPI_IO#(1) ifc_spi2;
    (*prefix="ddr"*)
    interface Ifc_axi4_master#(`AXI4ID, `paddr, 64, `User) ddr_slave;
    (*prefix="open"*)
    interface Ifc_axi4_master#(`AXI4ID, `paddr, 64, `User) open_slave;
    interface Ifc_axi4_slave #(`AXI4ID, `paddr, 64, `User) debug_master;
    interface Ifc_hart_to_debug debug_server;
`ifdef rtldump
    interface Get#(DumpType) io_dump;
`endif
  (*always_ready, always_enabled, prefix="qspi0"*)
  interface QSPI_out qspi_io;
endinterface:Ifc_Soc

(*synthesize*)
module mkSoc(Ifc_Soc);

    let debug_loop  <- mkdebug_loop;
    let bootrom     <- mkbootrom;
    let uart0       <- mkuart0;
    let bootconfig  <- mkbootconfig;
    let gpio        <- mkgpio;
    let clint       <- mkclint;
    let plic        <- mkplic;
    let ocm         <- mkocm;
    let pwm         <- mkpwm;
    let ccore       <- mkccore_axi4(`resetpc, 0);
    let qspi        <- mkqspi();

    let axi4_xbar   <- mkaxi4_crossbar;
    let axi4l_xbar  <- mkaxi4l_crossbar;
    let apb_fabric  <- mkapb_interconnect;

    let axi2apb     <- mkaxi2apb_bridge ;
    let axi2axil    <- mkaxi2axil_bridge ;

    Ifc_axi4_slave   #(`AXI4ID,`paddr, 64, `User) axi4_err    <- mkaxi4_err_2;
    Ifc_apb_slave    #(`paddr, 32, `User)         apb_err     <- mkapb_err;
    Ifc_axi4l_slave  #(`paddr, 32, `User)         axi4l_err   <- mkaxi4l_err_2;
    Ifc_spi_cluster spi_cluster <- mkspi_cluster;

 	  mkConnection(ccore.sb_clint_mtime, clint.device.sb_clint_mtime);
 	  mkConnection(ccore.sb_clint_mtip,  clint.device.sb_clint_mtip);
 	  mkConnection(ccore.sb_clint_msip,  clint.device.sb_clint_msip);

 	  mkConnection(ccore.sb_plic_meip, pack(plic.device.sb_to_targets[0]));
    mkConnection(plic.device.sb_frm_sources, {qspi.device.mv_interrupts, spi_cluster.spi2_sb_interrupt,
                      spi_cluster.spi1_sb_interrupt, spi_cluster.spi0_sb_interrupt,
                      pwm.device.sb_interrupt, uart0.device.interrupt,
                      gpio.device.sb_gpio_to_plic});

 	  mkConnection(ccore.master_d, axi4_xbar.v_from_masters[`DMem_master_num]);
 	  mkConnection(ccore.master_i, axi4_xbar.v_from_masters[`IMem_master_num]);

 	  mkConnection(axi4_xbar.v_to_slaves[`APBBridge_slave_num], axi2apb.axi4_side);
 	  mkConnection(axi2apb.apb_side, apb_fabric.frm_master);
 	  mkConnection(axi4_xbar.v_to_slaves[`AXI4LBridge_slave_num], axi2axil.axi4_side);
 	  mkConnection(axi2axil.axi4l_side, axi4l_xbar.v_from_masters[0]);
 	  mkConnection(axi4_xbar.v_to_slaves[`AXI4Err_slave_num], axi4_err);
 	  mkConnection(axi4_xbar.v_to_slaves[`QSPI_mem_slave_num], qspi.device.mem_slave);

    mkConnection(apb_fabric.v_to_slaves[`Debug_slave_num], debug_loop.slave);
    mkConnection(apb_fabric.v_to_slaves[`Rom_slave_num]  , bootrom.slave);
    mkConnection(apb_fabric.v_to_slaves[`Uart0_slave_num], uart0.slave);
    mkConnection(apb_fabric.v_to_slaves[`Pwm_slave_num],   pwm.slave);
    mkConnection(apb_fabric.v_to_slaves[`SPICluster_slave_num], spi_cluster.slave);
    mkConnection(apb_fabric.v_to_slaves[`Bootconfig_slave_num], bootconfig.slave);
    mkConnection(apb_fabric.v_to_slaves[`Gpio_slave_num],  gpio.slave);
    mkConnection(apb_fabric.v_to_slaves[`ApbErr_slave_num], apb_err);
 	  mkConnection(apb_fabric.v_to_slaves[`QSPI_cfg_slave_num], qspi.slave);

    mkConnection(axi4l_xbar.v_to_slaves[`Clint_slave_num], clint.slave);
    mkConnection(axi4l_xbar.v_to_slaves[`Plic_slave_num],  plic.slave);
    mkConnection(axi4l_xbar.v_to_slaves[`Ocm_slave_num ],  ocm.slave);
    mkConnection(axi4l_xbar.v_to_slaves[`AXI4LErr_slave_num], axi4l_err);


    interface ifc_uart0 = uart0.device.io;
    interface ifc_gpio  = gpio.device.io;
    interface ifc_pwm   = pwm.device.io;
    interface ifc_spi0  = spi_cluster.spi0_io;
    interface ifc_spi1  = spi_cluster.spi1_io;
    interface ifc_spi2  = spi_cluster.spi2_io;

    interface debug_master = axi4_xbar.v_from_masters[`Debug_master_num];
    interface debug_server = ccore.debug_server;

    interface ddr_slave    = axi4_xbar.v_to_slaves[`DDR_slave_num];
    interface open_slave   = axi4_xbar.v_to_slaves[`Open_slave_num];
    method boot_config = bootconfig.device.io;

`ifdef rtldump
    interface io_dump= ccore.io_dump;
`endif
  interface qspi_io = qspi.device.io;
  
  
endmodule:mkSoc

endpackage: Soc

